package biz.inspeed.test.reflact;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

import org.junit.Test;

public class ReflactTestCases {

	public  void methodA(List<String> list){
		String name = new Throwable().getStackTrace()[0].getMethodName();
		 System.out.println(name);
		 try {
			Method method = this.getClass().getMethod(name, List.class);
			ParameterizedType type = (ParameterizedType)method.getGenericParameterTypes()[0];
			Type[] types = type.getActualTypeArguments();
			System.out.println(types[0]);
			System.out.println();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
	}
	
	@Test
	public void testPameterType(){
		methodA(new ArrayList<String>());
	}
	@Test
	public void testCast(){
		Object obj = 1;
		int i = (Integer) obj;
		Assert.assertEquals(1, i);
		System.out.println(i);
	}
	
	@Test
	public void test() {
		Field[] fields = Cat.class.getDeclaredFields();
		Cat cat = new Cat("field-cat", 17);
		for(Field f : fields){
			try {
				f.setAccessible(true);
				System.out.println(f.get(cat));
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	@Test
	public void testDynamicReflact() {
		Work worker = (Work) Proxy.newProxyInstance(
				Work.class.getClassLoader(), new Class[] { Work.class },
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method,
							Object[] args) throws Throwable {
						System.out.println("this cat is working hard now...");
						return null;
					}
				});
		worker.work();
		Cat cat = new Cat("hello", 18);
		Cut cut = (Cut) Proxy.newProxyInstance(
				this.getClass().getClassLoader(), new Class[] { Cut.class },
				new InvocationHandler1(new CutImpl(cat)));
		System.out.println(cut.deByte(cut.toByte()));
	}

	/** define a interface to be implemented! */
	static interface Work {
		public void work();
	}

	/** define a simple class */
	static class Cat {
		private String name = "tom";
		private int age = 13;// /age is not by year but by month!!

		public Cat() {
		}

		public Cat(String name, int age) {
			this.name = name;
			this.age = age;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public int getAge() {
			return age;
		}

		public void setAge(int age) {
			this.age = age;
		}
	}

}

/** maybe a cat can cut itself into piceies & then get ok! */
interface Cut {
	public byte[] toByte();

	public Object deByte(byte[] b);
}

/** һ���򵥵�Ŷʵ�� */
class CutImpl implements Cut {
	private Object proxy;

	public CutImpl(Object proxy) {
		this.proxy = proxy;
	}

	public byte[] toByte() {
		Field[] fields = this.proxy.getClass().getDeclaredFields();
		StringBuffer sb = new StringBuffer(50);
		for (Field f : fields) {
			sb.append(f.getName()).append("--");
		}
		return sb.toString().getBytes();
	}

	public Object deByte(byte[] b) {
		return new String(b, 0, b.length);
		// return new String("hello world");
	}
}

/** self define a InvocationHandler to do my own business **/
class InvocationHandler1 implements InvocationHandler {
	Object proxy;

	public InvocationHandler1() {
	}

	public InvocationHandler1(CutImpl obj) {
		this.proxy = obj;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("proxy " + proxy.getClass().getCanonicalName());
		System.out.println("method " + method.getName());
		System.out.println("args " + String.valueOf(args));
		return method.invoke(this.proxy, args);
		// String name = method.getName();
		// if("toByte".equalsIgnoreCase(name)){
		// return toByte();
		// }else if("deByte".equalsIgnoreCase(name)){
		// return deByte(null);
		// }else{
		//
		// }
		// return null;
	}

}
